Introdução à Aprendizagem de Máquina com Tidymodels


XV Semana de Estatística - UFES, Vitória/ES
7 a 8 de novembro de 2024

Prof. Marcelo R. P. Ferreira

DE/UFPB – PPGMDS/UFPB

Qual é o nosso plano?

Dia 1:

  • Aprendizagem de máquina
    • Conceitos básicos;
    • Tipos de Aprendizagem de Máquina;
    • Dados estruturados e não-estruturados;
    • Pré-processamanto de dados;
    • Avaliação de modelos;
    • Particionamento de dados:
      • Holdout e \(K\)-fold cross-validation;
    • Otimização de hiperparâmetros:
      • Grid search e Grid search via racing.

Qual é o nosso plano?

Dia 2:

  • tidymodels
    • Introdução;
    • Particionamento de dados:rsample;
    • O que constitui um modelo: parsnip;
    • Pré-processamento e feature engineering: recipes;
    • Avaliação de modelos: yardstick;
    • Otimização de hiperparâmetros: tune;
    • Avaliando muitos modelos: workflowsets.

A biblioteca tidymodels

A biblioteca tidymodels

A biblioteca tidymodels

  • Assim como a tidyverse é uma meta-biblioteca que consiste de diversas bibliotecas como ggplot2 e dplyr, tidymodels é uma meta-biblioteca que consiste das seguintes bibliotecas:
    • rsample: funções para particionamento e reamostragem eficiente de dados;
    • parsnip: interface unificada para um amplo conjunto de modelos que podem ser testados sem que o usuário se preocupe com diferenças de sintaxe;
    • recipes: pré-processamento e feature engineering;
    • tune: otimização de hiperparâmetros;
    • yardstick: funções para avaliar a efetividade de modelos através de medidas de performance.

A biblioteca tidymodels

  • Outras bibliotecas são carregadas junto com tidymodels, como, por exemplo:
    • workflows: junta pré-processamento, modelagem (treinamento) e pós-processamento;
    • workflowsets: cria conjuntos de workflows;
    • broom: converte a informação contida em objetos comuns de R para o formato tidy;
    • dials: cria e gerencia hiperparâmetros de ajuste e grids de hiperparâmetros.
  • Bibliotecas adicionais dentro do fluxo de trabalho de aprendizagem de máquina:
    • finetune: permite um processo de otimização de hiperparâmetros mais eficiente;
    • DALEX: ferramentas oara interpretação de modelos;
    • DALEXtra: extensões para a biblioteca DALEX.

A biblioteca tidymodels

library(tidymodels)
── Attaching packages ────────────────────────────────────── tidymodels 1.1.0 ──
✔ broom        1.0.5      ✔ recipes      1.0.10
✔ dials        1.2.0      ✔ rsample      1.1.1 
✔ dplyr        1.1.2      ✔ tibble       3.2.1 
✔ ggplot2      3.5.1      ✔ tidyr        1.3.0 
✔ infer        1.0.4      ✔ tune         1.1.1 
✔ modeldata    1.1.0      ✔ workflows    1.1.3 
✔ parsnip      1.1.0      ✔ workflowsets 1.0.1 
✔ purrr        1.0.1      ✔ yardstick    1.2.0 
── Conflicts ───────────────────────────────────────── tidymodels_conflicts() ──
✖ purrr::discard() masks scales::discard()
✖ dplyr::filter()  masks stats::filter()
✖ dplyr::lag()     masks stats::lag()
✖ recipes::step()  masks stats::step()
• Use suppressPackageStartupMessages() to eliminate package startup messages

Conjunto de dados

  • Vamos considerar, inicialmente, um conjunto de dados bastante conhecido, o Palmer Station penguin data, que contém mensurações obtidas de diferentes espécies de pinguins.
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ forcats   1.0.0     ✔ readr     2.1.4
✔ lubridate 1.9.2     ✔ stringr   1.5.0
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ readr::col_factor() masks scales::col_factor()
✖ purrr::discard()    masks scales::discard()
✖ dplyr::filter()     masks stats::filter()
✖ stringr::fixed()    masks recipes::fixed()
✖ dplyr::lag()        masks stats::lag()
✖ readr::spec()       masks yardstick::spec()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
df <- read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-07-28/penguins.csv')
Rows: 344 Columns: 8
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): species, island, sex
dbl (5): bill_length_mm, bill_depth_mm, flipper_length_mm, body_mass_g, year

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Conjunto de dados

glimpse(df)
Rows: 344
Columns: 8
$ species           <chr> "Adelie", "Adelie", "Adelie", "Adelie", "Adelie", "A…
$ island            <chr> "Torgersen", "Torgersen", "Torgersen", "Torgersen", …
$ bill_length_mm    <dbl> 39.1, 39.5, 40.3, NA, 36.7, 39.3, 38.9, 39.2, 34.1, …
$ bill_depth_mm     <dbl> 18.7, 17.4, 18.0, NA, 19.3, 20.6, 17.8, 19.6, 18.1, …
$ flipper_length_mm <dbl> 181, 186, 195, NA, 193, 190, 181, 195, 193, 190, 186…
$ body_mass_g       <dbl> 3750, 3800, 3250, NA, 3450, 3650, 3625, 4675, 3475, …
$ sex               <chr> "male", "female", "female", NA, "female", "male", "f…
$ year              <dbl> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007…
df %>% summary()
   species             island          bill_length_mm  bill_depth_mm  
 Length:344         Length:344         Min.   :32.10   Min.   :13.10  
 Class :character   Class :character   1st Qu.:39.23   1st Qu.:15.60  
 Mode  :character   Mode  :character   Median :44.45   Median :17.30  
                                       Mean   :43.92   Mean   :17.15  
                                       3rd Qu.:48.50   3rd Qu.:18.70  
                                       Max.   :59.60   Max.   :21.50  
                                       NA's   :2       NA's   :2      
 flipper_length_mm  body_mass_g       sex                 year     
 Min.   :172.0     Min.   :2700   Length:344         Min.   :2007  
 1st Qu.:190.0     1st Qu.:3550   Class :character   1st Qu.:2007  
 Median :197.0     Median :4050   Mode  :character   Median :2008  
 Mean   :200.9     Mean   :4202                      Mean   :2008  
 3rd Qu.:213.0     3rd Qu.:4750                      3rd Qu.:2009  
 Max.   :231.0     Max.   :6300                      Max.   :2009  
 NA's   :2         NA's   :2                                       

Conjunto de dados

  • Por hora, vamos excluir as linhas que contém valores ausentes:
df <- df[complete.cases(df),]
  • Também vamos definir as variáveis qualitativas como fatores:
df <- df %>%
  mutate(across(where(is.character), as.factor))

glimpse(df)
Rows: 333
Columns: 8
$ species           <fct> Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adel…
$ island            <fct> Torgersen, Torgersen, Torgersen, Torgersen, Torgerse…
$ bill_length_mm    <dbl> 39.1, 39.5, 40.3, 36.7, 39.3, 38.9, 39.2, 41.1, 38.6…
$ bill_depth_mm     <dbl> 18.7, 17.4, 18.0, 19.3, 20.6, 17.8, 19.6, 17.6, 21.2…
$ flipper_length_mm <dbl> 181, 186, 195, 193, 190, 181, 195, 182, 191, 198, 18…
$ body_mass_g       <dbl> 3750, 3800, 3250, 3450, 3650, 3625, 4675, 3200, 3800…
$ sex               <fct> male, female, female, female, male, female, male, fe…
$ year              <dbl> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007…

Particionamento de dados:rsample

  • Vamos particionar o conjunto de dados em 75% para treinamento e 25% para teste;

  • Para isso, vamos utilizar a função initial_split() da biblioteca rsample.

set.seed(1326)
df_split <- df %>%
  initial_split(prop = .75, strata = sex)

df_split
<Training/Testing/Total>
<249/84/333>
  • Os conjuntos de treinamento e de teste são obtidos através das funções training() e testing(), respectivamente.
trn_df <- df_split %>%
  training()

tst_df <- df_split %>%
  testing()

Particionamento de dados:rsample

  • Com o conjunto de treinamento vamos gerar partições para um processo de validação cruzada com 5 folds, utilizando a função vfold_cv().
set.seed(1326)
df_cv <- trn_df %>%
  vfold_cv(v = 5, strata = sex)

df_cv
#  5-fold cross-validation using stratification 
# A tibble: 5 × 2
  splits           id   
  <list>           <chr>
1 <split [198/51]> Fold1
2 <split [199/50]> Fold2
3 <split [199/50]> Fold3
4 <split [200/49]> Fold4
5 <split [200/49]> Fold5

Análise exploratória de dados

  • Explore o conjunto de treinamento por conta própria!
    • Explore a distribuição da variável alvo, sex;
    • Verifique como se distribuem as variáveis numéricas;
    • Como a variável alvo, sex, se relaciona com a variável species?
    • Como a distribuição das variáveis numéricas difere entre as classes da variável alvo?

Análise exploratória de dados

trn_df %>%
  ggplot(aes(x = sex)) +
  geom_bar()

Análise exploratória de dados

trn_df %>%
  ggplot(aes(x = sex, fill = species)) +
  geom_bar()

Análise exploratória de dados

trn_df %>%
  ggplot(aes(x = sex, fill = island)) +
  geom_bar()

Análise exploratória de dados

trn_df %>%
  ggplot(aes(x = bill_length_mm, fill = sex, color = sex)) +
  geom_density(alpha = .7)

Análise exploratória de dados

trn_df %>%
  ggplot(aes(x = bill_depth_mm, fill = sex, color = sex)) +
  geom_density(alpha = .7)

Análise exploratória de dados

trn_df %>%
  ggplot(aes(x = flipper_length_mm, fill = sex, color = sex)) +
  geom_density(alpha = .7)

Análise exploratória de dados

trn_df %>%
  ggplot(aes(x = body_mass_g, fill = sex, color = sex)) +
  geom_density(alpha = .7)

Análise exploratória de dados

trn_df %>%
  ggplot(aes(flipper_length_mm, bill_length_mm, color = sex, size = body_mass_g)) +
  geom_point(alpha = 0.5) +
  facet_wrap(~species)

O que constitui um modelo: parsnip

  • Como você ajustaria um modelo linear em R?

  • Existem diversas maneiras de fazer isso, certo?

  • Por exemplo:

    • lm para o modelo de regressão linear clássico;
    • glm para modelos lineares generalizados;
    • glmnet para regressão linear com regularização;
    • gls para modelos lineares por mínimos quadrados generalizados;
    • keras para regressão usando TensorFlow;
    • spark para big data;
    • brulee para regressão usando torch

O que constitui um modelo: parsnip

  • Em R, existem diversas funções para o mesmo fim;

  • Essas funções, na maioria das vezes, possuem diferentes interfaces e recebem diferentes argumentos;

  • A biblioteca parsnip se propõe a resolver esse problema oferecendo uma interface padronizada.

O que constitui um modelo: parsnip

  • Para especificar um modelo com parsnip:
    • Escolha um modelo (model);
    • Especifique um motor computacional (engine);
    • Defina o modo (mode).

O que é cada parte dessas?

  • model: o tipo de modelo a ser utilizado. Por exemplo: regressão logística, redes neurais, floresta aleatória, etc.;

  • engine: a biblioteca a partir da qual model deve ser ajustado. Por exemplo: glmnet, nnet, ranger, etc.;

  • mode: especifica o tipo de tarefa: classificação (classification), regressão (regression) ou regressão para dados com censura (censored regression).

O que constitui um modelo: parsnip

  • Escolha um modelo (model):
rand_forest()
Random Forest Model Specification (unknown mode)

Computational engine: ranger 
  • Especifique um motor (engine):
rand_forest() %>%
  set_engine("randomForest")
Random Forest Model Specification (unknown mode)

Computational engine: randomForest 
  • Defina o modo:
rand_forest() %>%
  set_engine("randomForest") %>%
  set_mode("classification")
Random Forest Model Specification (classification)

Computational engine: randomForest 

O que constitui um modelo: parsnip





Todos os modelos disponíveis estão listados em: https://www.tidymodels.org/find/parsnip/

O que constitui um modelo: parsnip

O que constitui um modelo: parsnip

  • Vamos definir alguns modelos que usaremos a seguir.
tree_spec <- decision_tree() %>%
  set_engine("rpart") %>%
  set_mode("classification")

knn_spec <- nearest_neighbor() %>%
  set_engine("kknn") %>%
  set_mode("classification")

rf_spec <- rand_forest() %>%
  set_engine("ranger") %>%
  set_mode("classification")

log_spec <- logistic_reg() %>%
  set_engine("glm") %>%
  set_mode("classification")

svm_spec <- svm_rbf() %>%
  set_engine("kernlab") %>%
  set_mode("classification")

Fluxo de trabalho: workflows

  • Por que usar workflows?
    • workflows lida melhor com novos dados do que funções de R base em termos de novos níveis de fatores;
    • Pode ser usado em conjunto com outras ferramentas, como ferramentas de pré-processamento;
    • Ajuda na organização quando estamos trabalhando com múltiplos modelos;
    • workflows captura o processo de modelagem inteiro através das funções fit() e predict().

Fluxo de trabalho: workflows

tree_spec %>%
  fit(sex ~ bill_length_mm+bill_depth_mm+flipper_length_mm+body_mass_g, data = trn_df)
parsnip model object

n= 249 

node), split, n, loss, yval, (yprob)
      * denotes terminal node

 1) root 249 123 male (0.49397590 0.50602410)  
   2) body_mass_g< 3712.5 86  16 female (0.81395349 0.18604651)  
     4) bill_depth_mm< 18.55 64   2 female (0.96875000 0.03125000) *
     5) bill_depth_mm>=18.55 22   8 male (0.36363636 0.63636364)  
      10) bill_length_mm< 38.95 8   1 female (0.87500000 0.12500000) *
      11) bill_length_mm>=38.95 14   1 male (0.07142857 0.92857143) *
   3) body_mass_g>=3712.5 163  53 male (0.32515337 0.67484663)  
     6) bill_depth_mm< 14.85 41   4 female (0.90243902 0.09756098) *
     7) bill_depth_mm>=14.85 122  16 male (0.13114754 0.86885246) *

Fluxo de trabalho: workflows

workflow() %>%
  add_formula(sex ~ bill_length_mm+bill_depth_mm+flipper_length_mm+body_mass_g) %>%
  add_model(tree_spec) %>%
  fit(data = trn_df)
══ Workflow [trained] ══════════════════════════════════════════════════════════
Preprocessor: Formula
Model: decision_tree()

── Preprocessor ────────────────────────────────────────────────────────────────
sex ~ bill_length_mm + bill_depth_mm + flipper_length_mm + body_mass_g

── Model ───────────────────────────────────────────────────────────────────────
n= 249 

node), split, n, loss, yval, (yprob)
      * denotes terminal node

 1) root 249 123 male (0.49397590 0.50602410)  
   2) body_mass_g< 3712.5 86  16 female (0.81395349 0.18604651)  
     4) bill_depth_mm< 18.55 64   2 female (0.96875000 0.03125000) *
     5) bill_depth_mm>=18.55 22   8 male (0.36363636 0.63636364)  
      10) bill_length_mm< 38.95 8   1 female (0.87500000 0.12500000) *
      11) bill_length_mm>=38.95 14   1 male (0.07142857 0.92857143) *
   3) body_mass_g>=3712.5 163  53 male (0.32515337 0.67484663)  
     6) bill_depth_mm< 14.85 41   4 female (0.90243902 0.09756098) *
     7) bill_depth_mm>=14.85 122  16 male (0.13114754 0.86885246) *

Fluxo de trabalho: workflows

tree_fit <- workflow() %>%
  add_formula(sex ~ bill_length_mm+bill_depth_mm+flipper_length_mm+body_mass_g) %>%
  add_model(tree_spec) %>%
  fit(data = trn_df)

tree_fit
══ Workflow [trained] ══════════════════════════════════════════════════════════
Preprocessor: Formula
Model: decision_tree()

── Preprocessor ────────────────────────────────────────────────────────────────
sex ~ bill_length_mm + bill_depth_mm + flipper_length_mm + body_mass_g

── Model ───────────────────────────────────────────────────────────────────────
n= 249 

node), split, n, loss, yval, (yprob)
      * denotes terminal node

 1) root 249 123 male (0.49397590 0.50602410)  
   2) body_mass_g< 3712.5 86  16 female (0.81395349 0.18604651)  
     4) bill_depth_mm< 18.55 64   2 female (0.96875000 0.03125000) *
     5) bill_depth_mm>=18.55 22   8 male (0.36363636 0.63636364)  
      10) bill_length_mm< 38.95 8   1 female (0.87500000 0.12500000) *
      11) bill_length_mm>=38.95 14   1 male (0.07142857 0.92857143) *
   3) body_mass_g>=3712.5 163  53 male (0.32515337 0.67484663)  
     6) bill_depth_mm< 14.85 41   4 female (0.90243902 0.09756098) *
     7) bill_depth_mm>=14.85 122  16 male (0.13114754 0.86885246) *

Fluxo de trabalho: workflows

predict(tree_fit, new_data = tst_df)
# A tibble: 84 × 1
   .pred_class
   <fct>      
 1 male       
 2 female     
 3 female     
 4 male       
 5 female     
 6 female     
 7 male       
 8 male       
 9 male       
10 male       
# ℹ 74 more rows

Fluxo de trabalho: workflows

tree_fit %>% augment(new_data = tst_df)
# A tibble: 84 × 11
   species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
   <fct>   <fct>              <dbl>         <dbl>             <dbl>       <dbl>
 1 Adelie  Torgersen           39.5          17.4               186        3800
 2 Adelie  Torgersen           41.1          17.6               182        3200
 3 Adelie  Biscoe              37.8          18.3               174        3400
 4 Adelie  Biscoe              38.8          17.2               180        3800
 5 Adelie  Biscoe              37.9          18.6               172        3150
 6 Adelie  Dream               39.5          17.8               188        3300
 7 Adelie  Dream               40.9          18.9               184        3900
 8 Adelie  Dream               39.2          21.1               196        4150
 9 Adelie  Dream               40.8          18.4               195        3900
10 Adelie  Dream               42.3          21.2               191        4150
# ℹ 74 more rows
# ℹ 5 more variables: sex <fct>, year <dbl>, .pred_class <fct>,
#   .pred_female <dbl>, .pred_male <dbl>
tree_predictions <- tree_fit %>% augment(new_data = tst_df)
tree_predictions$.pred_class
 [1] male   female female male   female female male   male   male   male  
[11] male   male   female female male   female male   male   female male  
[21] male   female female female male   male   female female male   male  
[31] female female male   male   female male   male   male   male   female
[41] female female female male   female female male   female male   male  
[51] female female female female male   male   male   female male   male  
[61] male   male   female male   female male   female male   male   male  
[71] male   female male   female male   female female male   male   female
[81] male   female male   male  
Levels: female male

Fluxo de trabalho: workflows

library(rpart.plot)
Loading required package: rpart

Attaching package: 'rpart'
The following object is masked from 'package:dials':

    prune
tree_fit %>%
  extract_fit_engine() %>%
  rpart.plot(roundint = FALSE)

Avaliação de modelos: yardstick

  • Como avaliamos se um modelo tem bom desempenho?

  • A biblioteca yardstick sornece funções para calcular diversas métricas de avaliação.

tree_fit %>%
  augment(new_data = tst_df) %>%
  conf_mat(truth = sex, estimate = .pred_class)
          Truth
Prediction female male
    female     35    2
    male        7   40
tree_fit %>%
  augment(new_data = tst_df) %>%
  metrics(truth = sex, estimate = .pred_class)
# A tibble: 2 × 3
  .metric  .estimator .estimate
  <chr>    <chr>          <dbl>
1 accuracy binary         0.893
2 kap      binary         0.786

Avaliação de modelos: yardstick

tree_fit %>%
  augment(new_data = tst_df) %>%
  conf_mat(truth = sex, estimate = .pred_class) %>%
  autoplot(type = "heatmap")

Avaliação de modelos: yardstick

tree_fit %>%
  augment(new_data = tst_df) %>%
  accuracy(truth = sex, estimate = .pred_class)
# A tibble: 1 × 3
  .metric  .estimator .estimate
  <chr>    <chr>          <dbl>
1 accuracy binary         0.893
tree_fit %>%
  augment(new_data = tst_df) %>%
  sensitivity(truth = sex, estimate = .pred_class)
# A tibble: 1 × 3
  .metric     .estimator .estimate
  <chr>       <chr>          <dbl>
1 sensitivity binary         0.833
tree_fit %>%
  augment(new_data = tst_df) %>%
  specificity(truth = sex, estimate = .pred_class)
# A tibble: 1 × 3
  .metric     .estimator .estimate
  <chr>       <chr>          <dbl>
1 specificity binary         0.952

Avaliação de modelos: yardstick

penguins_metrics <- metric_set(accuracy, specificity, sensitivity, precision)

tree_fit %>%
  augment(new_data = tst_df) %>%
  penguins_metrics(truth = sex, estimate = .pred_class)
# A tibble: 4 × 3
  .metric     .estimator .estimate
  <chr>       <chr>          <dbl>
1 accuracy    binary         0.893
2 specificity binary         0.952
3 sensitivity binary         0.833
4 precision   binary         0.946
tree_fit %>%
  augment(new_data = tst_df) %>%
  group_by(species) %>%
  penguins_metrics(truth = sex, estimate = .pred_class)
# A tibble: 12 × 4
   species   .metric     .estimator .estimate
   <fct>     <chr>       <chr>          <dbl>
 1 Adelie    accuracy    binary         0.889
 2 Chinstrap accuracy    binary         0.875
 3 Gentoo    accuracy    binary         0.906
 4 Adelie    specificity binary         0.944
 5 Chinstrap specificity binary         1    
 6 Gentoo    specificity binary         0.938
 7 Adelie    sensitivity binary         0.833
 8 Chinstrap sensitivity binary         0.75 
 9 Gentoo    sensitivity binary         0.875
10 Adelie    precision   binary         0.938
11 Chinstrap precision   binary         1    
12 Gentoo    precision   binary         0.933

Avaliação de modelos: yardstick

tree_fit %>%
  augment(new_data = tst_df) %>%
  roc_curve(truth = sex, .pred_female)
# A tibble: 7 × 3
  .threshold specificity sensitivity
       <dbl>       <dbl>       <dbl>
1  -Inf           0            1    
2     0.0714      0            1    
3     0.131       0.0714       0.952
4     0.875       0.952        0.833
5     0.902       0.976        0.786
6     0.969       1            0.452
7   Inf           1            0    
tree_fit %>%
  augment(new_data = tst_df) %>%
  roc_auc(truth = sex, .pred_female)
# A tibble: 1 × 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 roc_auc binary         0.890

Avaliação de modelos: yardstick

tree_fit %>%
  augment(new_data = tst_df) %>%
  roc_curve(truth = sex, .pred_female) %>%
  autoplot()

Pré-processamento e feature engineering: recipes

  • Podemos querer modificar nossas variáveis por diversas razões:
    • O modelo requer que uma ou mais variáveis estejam em um formato específico (por exemplo, variáveis dummy para regressão linear);
    • O modelo precisa que os dados tenham certas características (por exemplo, mesma escala para o \(K\)-NN);
    • A saída é melhor predita quando uma ou mais colunas são transformadas de alguma forma (também conhecido por “engenharia de atributos” ou “feature engineering”).
      • Interações;
      • Exansões polinomiais;
      • Componentes principais;
      • Dentre outras.

Pré-processamento e feature engineering: recipes

  • A biblioteca recipes possui diversas funções para pré-processamento e feature engineering;

  • Uma “receita” é uma descrição de passos a serem executados em um conjunto de dados com o objetivo de prepará-lo para a análise.

recipe(y ~ x1 + x2, data = df) %>%
  step_*() %>%
  step_*() ...
  • Na receita, precisamos especificar a relação entre a variável de saída e as variáveis preditoras (uma fórmula) e o conjunto de dados;

  • Os passos são definidos pelos step_*(), onde * especifica a transformação desejada.

Pré-processamento e feature engineering: recipes

penguins_rec <- recipe(sex ~ ., data = trn_df)

penguins_rec %>% summary()
# A tibble: 8 × 4
  variable          type      role      source  
  <chr>             <list>    <chr>     <chr>   
1 species           <chr [3]> predictor original
2 island            <chr [3]> predictor original
3 bill_length_mm    <chr [2]> predictor original
4 bill_depth_mm     <chr [2]> predictor original
5 flipper_length_mm <chr [2]> predictor original
6 body_mass_g       <chr [2]> predictor original
7 year              <chr [2]> predictor original
8 sex               <chr [3]> outcome   original
  • Esta receita apenas define os papeis de cada variável na análise.

Pré-processamento e feature engineering: recipes

  • step_dummy(): cria variáveis dummy para preditores definidos como fatores;

  • step_normalize(): realiza padronização de variáveis preditoras;

  • step_zv(): elimina preditores com variância zero;

  • step_corr(): útil para lidar com preditores altamente correlacionados, encontrando o conjunto de preditores cujas correlações são menores do que um limiar;

  • step_pca(): extração de componentes principais;

  • Muito mais em: https://www.tidymodels.org/find/recipes/.

Pré-processamento e feature engineering: recipes

penguins_rec <- recipe(sex ~ ., data = trn_df) %>%
  step_zv(all_predictors()) %>%
  step_normalize(all_numeric_predictors()) %>%
  step_corr(all_numeric_predictors(), threshold = 0.9) %>%
  step_dummy(all_nominal_predictors()) %>%
  step_poly(body_mass_g, degree = 2)
  • prep(): estima os parâmetros dos passos definidos na receita para o conjunto de treinamento. Podemos aplicar esses passos a um outro conjunto de interesse, tipicamente, o conjunto de teste;

  • juice(): aplica os passos definidos na receita ao conjunto de dados de interesse.

prepped_df <- penguins_rec %>%
  prep() %>%
  juice()

Pré-processamento e feature engineering: recipes

prepped_df
# A tibble: 249 × 11
   bill_length_mm bill_depth_mm flipper_length_mm  year sex    species_Chinstrap
            <dbl>         <dbl>             <dbl> <dbl> <fct>              <dbl>
 1         -0.656         0.393            -0.443 -1.26 female                 0
 2         -1.30          1.05             -0.589 -1.26 female                 0
 3         -0.907         0.293            -1.46  -1.26 female                 0
 4         -1.32          0.293            -1.17  -1.26 female                 0
 5         -0.943         0.896            -0.443 -1.26 female                 0
 6         -1.72          0.594            -1.24  -1.26 female                 0
 7         -1.45          0.996            -0.880 -1.26 female                 0
 8         -1.55          0.846            -1.03  -1.26 female                 0
 9         -0.620         0.343            -1.03  -1.26 female                 0
10         -0.800        -0.260            -1.68  -1.26 female                 0
# ℹ 239 more rows
# ℹ 5 more variables: species_Gentoo <dbl>, island_Dream <dbl>,
#   island_Torgersen <dbl>, body_mass_g_poly_1 <dbl>, body_mass_g_poly_2 <dbl>
  • Ao usarmos workflows, no entanto, não há a necessidade de “extrair” com prep() e juice() os dados transformados pela receita, pois isso será feito implicitamente.

Pré-processamento e feature engineering: recipes

set.seed(1326)

penguins_lr_wflow <- workflow() %>%
  add_recipe(penguins_rec) %>%
  add_model(log_spec)

lr_fit <- penguins_lr_wflow %>%
  fit(data = trn_df)

Pré-processamento e feature engineering: recipes

lr_fit
══ Workflow [trained] ══════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: logistic_reg()

── Preprocessor ────────────────────────────────────────────────────────────────
5 Recipe Steps

• step_zv()
• step_normalize()
• step_corr()
• step_dummy()
• step_poly()

── Model ───────────────────────────────────────────────────────────────────────

Call:  stats::glm(formula = ..y ~ ., family = stats::binomial, data = data)

Coefficients:
       (Intercept)      bill_length_mm       bill_depth_mm   flipper_length_mm  
            6.4872              3.8063              2.8166              0.1141  
              year   species_Chinstrap      species_Gentoo        island_Dream  
           -0.3346             -7.8719            -12.1981              0.6236  
  island_Torgersen  body_mass_g_poly_1  body_mass_g_poly_2  
           -0.2209            109.2831             27.0910  

Degrees of Freedom: 248 Total (i.e. Null);  238 Residual
Null Deviance:      345.2 
Residual Deviance: 86.22    AIC: 108.2

Pré-processamento e feature engineering: recipes

lr_fit %>% tidy(conf.int = TRUE)
# A tibble: 11 × 7
   term               estimate std.error statistic   p.value conf.low conf.high
   <chr>                 <dbl>     <dbl>     <dbl>     <dbl>    <dbl>     <dbl>
 1 (Intercept)           6.49      2.10      3.08  0.00205       2.90    11.4  
 2 bill_length_mm        3.81      0.944     4.03  0.0000554     2.12     5.87 
 3 bill_depth_mm         2.82      0.793     3.55  0.000384      1.41     4.56 
 4 flipper_length_mm     0.114     0.983     0.116 0.908        -1.81     2.08 
 5 year                 -0.335     0.348    -0.962 0.336        -1.05     0.336
 6 species_Chinstrap    -7.87      2.20     -3.58  0.000347    -12.7     -3.98 
 7 species_Gentoo      -12.2       4.29     -2.84  0.00450     -22.1     -4.78 
 8 island_Dream          0.624     0.941     0.663 0.507        -1.20     2.54 
 9 island_Torgersen     -0.221     0.992    -0.223 0.824        -2.20     1.75 
10 body_mass_g_poly_1  109.       34.1       3.21  0.00135      57.5    196.   
11 body_mass_g_poly_2   27.1      18.8       1.44  0.150        -3.29    71.8  

Pré-processamento e feature engineering: recipes




“Eu tava pensando nas receitas que eu vou fazer quando eu voltar pro Brasil”

Otimização de hiperparâmetros: tune

Avaliando muitos modelos: workflowsets

Fim

Obrigado pela Atenção!

Marcelo Rodrigo Portela Ferreira
marcelorpf@gmail.com
Material disponível em: http://www.de.ufpb.br/~marcelo